#include "KDebugServer.h"
#include "KDebugDef.h"
#include "KPackage.h"
#include "KSockAddress.h"
#include "KSocket.h"

KDebugActionPasv::KDebugActionPasv(KPageList *pool) : KStreamAction(pool)
{
}

KDebugServer *KDebugActionPasv::server() const
{
    return static_cast<KDebugServer *>(item());
}

bool KDebugActionPasv::sendPackage(const KPackage &pack)
{
    return post(pack.data(), pack.length());
}

void KDebugActionPasv::abortImp()
{
    KSocket *sock = socket();
    sock->shutdown();
    sock->close();
    server()->removeClient(this);
}

void KDebugActionPasv::onError(KDef::SockError type, DWORD error)
{
    abortOnce();
}

void KDebugActionPasv::onReceived(KKey *&key, void *data, size_t length, bool more)
{
    receive();
}

KDebugServer::KDebugServer(KPageList *pool, u_short port)
    : m_pool(pool), m_port(port), m_port_used(0)
{
}

void KDebugServer::setAttr(uint32_t backColor, uint32_t foreColor)
{
    if (!m_clients.empty()) {
        KPackage pack(sizeof(DebugHeader) + sizeof(DebugAttr));
        pack.append(DebugHeader(DebugHeader::Attr))
            .append(DebugAttr(backColor, foreColor));
        sendToClients(pack);
    }
}

void KDebugServer::setInfo(const std::string &info, bool title)
{
    if (!info.empty()) {
#ifdef K_LIB_DBG_OFF
        if (!title) {
            KTraceMsg("%s", info.c_str());
        }
#endif
        if (!m_clients.empty()) {
            KPackage pack(sizeof(DebugHeader) + sizeof(DebugInfo) + info.length());
            pack.append(DebugHeader(DebugHeader::Info))
                .append(DebugInfo((title ? 1 : 0), info.length()))
                .append(info.c_str(), info.length());
            sendToClients(pack);
        }
    }
}

void KDebugServer::onStarted()
{
    KIpAddress addr(m_port);
    if (KSocket *sock = addAcceptor(addr)) {
        sock->getLocalAddress(addr);
        m_port_used = addr.port();
    }
}

void KDebugServer::onStopped()
{
    m_clients.clear();
    m_port_used = 0;
}

void KDebugServer::onAccepted(KSocket *sock, KKey *key)
{
    KAutoPtr<KDebugActionPasv> action(new KDebugActionPasv(m_pool));
    sock->setKeepAlive(true, 5000, 1000);
    if (setAction(sock, action)) {
        {
            KLocker lock(*this);
            m_clients.insert(action);
        }
        action.release();
        receive(sock);
    }
}

void KDebugServer::removeClient(KDebugActionPasv *client)
{
    KLocker lock(*this);
    m_clients.erase(client);
}

void KDebugServer::sendToClients(const KPackage &pack)
{
    KDebugActionPasv *action;
    KLocker lock(*this);
    std::vector<KDebugActionPasv *> clients(m_clients.cbegin(), m_clients.cend());
    for (auto i = clients.cbegin(); i != clients.cend(); ++i) {
        action = *i;
        action->sendPackage(pack);
    }
}